package com.sumainfor.common.visitor;

import com.google.common.collect.Lists;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.*;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.*;
import net.sf.jsqlparser.util.cnfexpression.MultiAndExpression;
import net.sf.jsqlparser.util.cnfexpression.MultipleExpression;

import java.util.List;

/**
 * @Author Jack Chen
 * @Create 2019-01-18 18:06
 */
public class FromItemVisitorImpl implements FromItemVisitor {
    /**
     * 声明增强条件
     */
    private Expression enhancedCondition;

    private CustomExpressionEntity expreseEntity;

    public FromItemVisitorImpl(CustomExpressionEntity expreseEntity) {
        if (expreseEntity == null) {
            throw new NullPointerException("Sql增强器不能为空");
        }
        this.expreseEntity = expreseEntity;
    }

    /**
     * FROM 表名 <----主要的就是这个，判断用户对这个表有没有权限
     *
     * @param tableName
     */
    @Override
    public void visit(Table tableName) {
        //判断该表是否是需要操作的表
        if (isActionTable(tableName.getFullyQualifiedName())) {

            List<Expression> expressions = Lists.newArrayList();
            for (int i = 0; i < expreseEntity.getWhere().size(); i++) {
                CustomExpressionEntity.ItemEntity entity = expreseEntity.getWhere().get(i);
                Column column = new Column(new Table(tableName.getAlias() != null ? tableName.getAlias().getName() : tableName.getFullyQualifiedName()), entity.getField());
                if (entity.getAction().equals("in")) {
                    InExpression inExpression = new InExpression();
                    ItemsList list = new ExpressionList((List<Expression>) entity.getVal());
                    inExpression.setLeftExpression(column);
                    inExpression.setRightItemsList(list);
                    expressions.add(inExpression);
                } else {
                    //其他的
                    expressions.add(this.getOperator(entity.getAction(), new Expression[]{column, (Expression) entity.getVal()}));
                }
            }

            MultipleExpression multipleExpression = new MultiAndExpression(expressions);

            if (this.enhancedCondition != null) {
                enhancedCondition = new AndExpression(enhancedCondition, multipleExpression);
            } else {
                enhancedCondition = multipleExpression;
            }
        }
    }

    // FROM 子查询
    @Override
    public void visit(SubSelect subSelect) {
        // 如果是子查询的话返回到select接口实现类
        subSelect.getSelectBody().accept(new SelectVisitorImpl(expreseEntity));
    }

    // FROM subjoin
    @Override
    public void visit(SubJoin subjoin) {
        subjoin.getLeft().accept(new FromItemVisitorImpl(expreseEntity));
        for (Join join : subjoin.getJoinList()) {
            join.getRightItem().accept(new FromItemVisitorImpl(expreseEntity));
        }
    }

    // FROM 横向子查询
    @Override
    public void visit(LateralSubSelect lateralSubSelect) {
        lateralSubSelect.getSubSelect().getSelectBody()
                .accept(new SelectVisitorImpl(expreseEntity));
    }

    // FROM value列表
    @Override
    public void visit(ValuesList valuesList) {
    }

    // FROM tableFunction
    @Override
    public void visit(TableFunction tableFunction) {
    }

    @Override
    public void visit(ParenthesisFromItem aThis) {

    }

    /**
     * 将字符串类型的运算符转换成数据库运算语句
     *
     * @param op
     * @param exp
     * @return
     */
    private Expression getOperator(String op, Expression[] exp) {
        if ("=".equals(op)) {
            EqualsTo eq = new EqualsTo();
            eq.setLeftExpression(exp[0]);
            eq.setRightExpression(exp[1]);
            return eq;
        } else if (">".equals(op)) {
            GreaterThan gt = new GreaterThan();
            gt.setLeftExpression(exp[0]);
            gt.setRightExpression(exp[1]);
            return gt;
        } else if (">=".equals(op)) {
            GreaterThanEquals geq = new GreaterThanEquals();
            geq.setLeftExpression(exp[0]);
            geq.setRightExpression(exp[1]);
            return geq;
        } else if ("<".equals(op)) {
            MinorThan mt = new MinorThan();
            mt.setLeftExpression(exp[0]);
            mt.setRightExpression(exp[1]);
            return mt;
        } else if ("<=".equals(op)) {
            MinorThanEquals leq = new MinorThanEquals();
            leq.setLeftExpression(exp[0]);
            leq.setRightExpression(exp[1]);
            return leq;
        } else if ("<>".equals(op)) {
            NotEqualsTo neq = new NotEqualsTo();
            neq.setLeftExpression(exp[0]);
            neq.setRightExpression(exp[1]);
            return neq;
        } else if ("is null".equalsIgnoreCase(op)) {
            IsNullExpression isNull = new IsNullExpression();
            isNull.setNot(false);
            isNull.setLeftExpression(exp[0]);
            return isNull;
        } else if ("is not null".equalsIgnoreCase(op)) {
            IsNullExpression isNull = new IsNullExpression();
            isNull.setNot(true);
            isNull.setLeftExpression(exp[0]);
            return isNull;
        } else if ("like".equalsIgnoreCase(op)) {
            LikeExpression like = new LikeExpression();
            like.setNot(false);
            like.setLeftExpression(exp[0]);
            like.setRightExpression(exp[1]);
            return like;
        } else if ("not like".equalsIgnoreCase(op)) {
            LikeExpression nlike = new LikeExpression();
            nlike.setNot(true);
            nlike.setLeftExpression(exp[0]);
            nlike.setRightExpression(exp[1]);
            return nlike;
        } else if ("between".equalsIgnoreCase(op)) {
            Between bt = new Between();
            bt.setNot(false);
            bt.setLeftExpression(exp[0]);
            bt.setBetweenExpressionStart(exp[1]);
            bt.setBetweenExpressionEnd(exp[2]);
            return bt;
        } else if ("not between".equalsIgnoreCase(op)) {
            Between bt = new Between();
            bt.setNot(true);
            bt.setLeftExpression(exp[0]);
            bt.setBetweenExpressionStart(exp[1]);
            bt.setBetweenExpressionEnd(exp[2]);
            return bt;
        } else {
            return null;
        }

    }

    public Expression getEnhancedCondition() {
        return enhancedCondition;
    }

    /**
     * 判断传入的table是否是要进行操作的table
     *
     * @param tableName
     * @return
     */
    public boolean isActionTable(String tableName) {
        // 默认为操作
        boolean flag = true;
        // 无需操作的表的表名
        List<String> tableNames = expreseEntity.getIgnoreTableList();
        // 由于sql可能格式不规范可能表名会存在小写，故全部转换成大写,最上面的方法一样
        if (tableNames == null || tableNames.contains(tableName)) {
            // 如果表名在过滤条件中则将flag改为 false
            flag = false;
        }
        return flag;
    }
}
